// Environment code for project restaurant.mas2j

import jason.asSyntax.Literal;
import jason.asSyntax.NumberTerm;
import jason.asSyntax.Plan;
import jason.asSyntax.Structure;
import jason.asSyntax.Term;
import jason.environment.Environment;
import jason.functions.ceil;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;

import sun.awt.Mutex;

public class RestaurantEnv extends Environment {

	public static final String    PREND_COMMANDE = "prendCommande";
	public static final String    MOVE_NEXT_CASE = "moveNextCase";
	public static final String    SERT_COMMANDE = "sertCommande";
	public static final String    PREPARE_COMMANDE = "prepareCommande";
	public static final String    ENREGISTRE_COMMANDE = "enregistreCommande";
	public static final String    ENREGISTRE_SERVEUR = "enregistreServeur";
	public static final String    ENREGISTRE_CUISINIER = "enregistreCuisinier";
	public static final String    DEMANDE_ATTR_COMMANDE = "demandeAttributionCommande";
	public static final String    PLUS_COURT_CHEMIN = "cherchePlusCourtChemin";
	public static final String    CONFIRME_ENREGISTRE_SERVEUR = "confirmeEnregistreServeur";
	public static final String    DISTRIBUE_COMMANDE = "distribueCommande";
	public static final String    PREND_COMMANDE_AU_CUISINIER = "prendCommandeAuCuisinier";
	public static final String    PLAT_ATTRIBUE = "platAttribue";
	public static final String    PREPARE_PLAT = "preparePlat";
	public static final String    DEFINE_QUALITE = "defineQualite";
	public static final String 	  PLAT_TERMINE = "platTermine";

	//Etat de chaque celule
	public static final int CASE_VIDE = -1;
	public static final int CASE_SERVEUR = 0;
	public static final int CASE_CUISINIER = 1;
	public static final int CASE_FOUR = 2;
	public static final int CASE_TABLE_CUISINE = 3;
	public static final int CASE_TABLE_NO = 4;
	public static final int CASE_TABLE_SO = 5;
	public static final int CASE_TABLE_NE = 6;
	public static final int CASE_TABLE_SE = 7;

	public static final int SALLE = 0;
	public static final int CUISINE = 1;

	//Maximun des resources
	public static final int MAX_CUISINIERS = 4;
	public static final int MAX_SERVEURS = 3;
	//public static final int MAX_CLIENTS = 3;
	static final int PLATS_PAR_FOUR = 4; //(doit etre pair!)
	static final int PLATS_PAR_TABLE_CUISINE = 4; 
	static final int COMMANDES_PAR_CUISINIER = 4;
	//static final int PLATS_PAR_CUISINIER = 4;
	static final int MAX_FOURS = 3;
	static final int MAX_TABLES_CUISINE = 3;
	static final int MAX_TABLES = 9; //pour une perfect affichage, il faut etre proportionel a 3
	static final int PLATS_PAR_TABLE = 3; //Entre + Plat_Principal + Dessert

	static final int TAILLE_DE_CUISINE_X = 10;
	static final int TAILLE_DE_CUISINE_Y = 3;

	static final int TAILLE_DE_RESTAURANT_X = 10;
	static final int TAILLE_DE_RESTAURANT_Y = 8;

	static final int DUREE_DEPLACEMENT = 300;


	private Logger logger = Logger.getLogger("restaurant.mas2j."+RestaurantEnv.class.getName());
	public HashMap<Integer, LinkedList<Integer>[]> nouvellesCommandes;
	private RunnerEnv runner;
	private RestaurantAff fenetre;

	//Apres decision de reprendre le code a zero


	//    public RestaurantAff Paneau_dAffichage;

	//Apres decision de reprendre le code a zero

	private LinkedList<String> listeServeurs;

	private LinkedList<String> listeCuisiniers;
	private LinkedList<String> listeChefs;

	private LinkedList<Integer> commandesEnregistrees;
	private LinkedList<String> logDeCuisiniersEtCommandes;
	private HashMap<String, Integer> listeDePlatsPretsdeChaqueCuisinier;

	private int nbDePlatAvecQualiteSuper = 0;
	private Mutex verrou;

	//TODO: list de trucs
	private int[][] map;

	/** Called before the MAS execution with the args informed in .mas2j */

	@Override
	public void init(String[] args) {
		super.init(args);
		nouvellesCommandes = new HashMap<Integer, LinkedList<Integer>[]>();
		fenetre = new RestaurantAff();
		runner = new RunnerEnv(this, fenetre);
		runner.start();
		listeServeurs = new LinkedList<String>();
		listeCuisiniers = new LinkedList<String>();
		listeChefs = new LinkedList<String>();
		listeChefs = new LinkedList<String>();
		commandesEnregistrees = new LinkedList<Integer>();
		logDeCuisiniersEtCommandes = new LinkedList<String>();
		listeDePlatsPretsdeChaqueCuisinier = new HashMap<String, Integer>();
		map = new int[TAILLE_DE_RESTAURANT_X][TAILLE_DE_RESTAURANT_Y];
		verrou = new Mutex();

		addTempPercept();
		createLocalMap();
	}








	@Override
	public boolean executeAction(String agName, Structure action) {
		//		Traitement des actions diverses

		if(action.getFunctor().equals(DEMANDE_ATTR_COMMANDE)){
			demandeAttributionCommande(agName, action.getTerm(0), action.getTerm(1));
		}
		else if(action.getFunctor().equals(ENREGISTRE_COMMANDE)){
			enregistreCommande(agName, action.getTerm(0));
		}
		else if(action.getFunctor().equals(DISTRIBUE_COMMANDE)){
			distribueCommande(agName, action.getTerm(0),  action.getTerm(1), action.getTerm(2), action.getTerm(3));
		}
		else if(action.getFunctor().equals(CONFIRME_ENREGISTRE_SERVEUR)){
			confirmeEnregistreServeur(agName, action.getTerm(0),action.getTerm(1));
		}
		else if(action.getFunctor().equals(ENREGISTRE_SERVEUR)){
			return enregistreServeur(agName);
		}
		else if(action.getFunctor().equals(ENREGISTRE_CUISINIER)){
			return enregistreCuisinier(agName, action.getTerm(0));
		}
		else if(action.getFunctor().equals(MOVE_NEXT_CASE)){
			return moveNextCase(agName, action.getTerm(0), action.getTerm(1), 
					action.getTerm(2), action.getTerm(3));
		}
		else if(action.getFunctor().equals(PREND_COMMANDE_AU_CUISINIER)){
			return prendCommandeAuCuisinier(agName, action.getTerm(0), action.getTerm(1), 
					action.getTerm(2), action.getTerm(3));
		}
		else if(action.getFunctor().equals(PLAT_ATTRIBUE)){
			return platAttribue(agName, action.getTerm(0), action.getTerm(1), 
					action.getTerm(2));
		}
		else if(action.getFunctor().equals(PREPARE_PLAT)){
			return preparePlat(agName, action.getTerm(0), action.getTerm(1), 
					action.getTerm(2), action.getTerm(3), action.getTerm(4));
		}
		else if(action.getFunctor().equals(DEFINE_QUALITE)){
			return defineQualite(agName, action.getTerm(0), action.getTerm(1));
		}
		else if(action.getFunctor().equals(PLAT_TERMINE)){
			return platTermine(agName, action.getTerm(0), action.getTerm(1), 
					action.getTerm(2));
		}
		else{
			logger.info("executing: "+action+", but not implemented!");
		}
		return true;
	}


	private boolean prendCommandeAuCuisinier(String agName, Term term,Term term2, Term term3, Term term4) {

		String cuisinier = term4.toString();
		System.out.println(agName +" essaye de remove un plat du cuisinier "+cuisinier);
		fenetre.remove_plat_a_table_cuisine(cuisinier);
		return true;
	}


	private void distribueCommande(String agName, Term idCommande, Term table, Term typePlat,
			Term positionSurTable) {
		int nbPlat, nTable, pos;
		pos = Integer.parseInt(positionSurTable.toString());
		//		Numéro de la table, il existe surement  plus propre mais bon...
		nTable = Integer.parseInt(""+table.toString().charAt(table.toString().length()-1));
		if(typePlat.toString().equals("entree")){
			nbPlat=0;
		}
		else if(typePlat.toString().equals("plat")){
			nbPlat=1;
		}
		else if(typePlat.toString().equals("dessert")){
			nbPlat=2;
		}
		else{
			nbPlat=0;
		}
		//Calcul de la position de la table
		int x = 1+3*((nTable-1)%3);
		int y = 5 + 2*((nTable-1)/3);
		if(pos % 2 ==1){
			x++;
		}
		if(pos/2 == 1){
			y++;
		}
		logger.info("TypePlat = "+typePlat.toString()+" nbPlat = "+nbPlat);
		fenetre.add_plat_a_table(x, y, nbPlat);
	}








	private synchronized boolean moveNextCase(String agName, Term term, Term term2,
			Term term3, Term term4) {
		//	Integer x = Integer.parseInt(term.toString());
		//	Integer y = Integer.parseInt(term2.toString()) - TAILLE_DE_CUISINE_Y;
		Integer a = Integer.parseInt(term3.toString());
		Integer b = Integer.parseInt(term4.toString()) - TAILLE_DE_CUISINE_Y;
		//	logger.info("ben voila : "+agName+" : "+term+", "+term2+", "+term3+", "+term4);
		int direction = cherchePlusCourtChemin(agName, term, term2, term3, term4);

		int a2, b2;
		switch(direction){
		case -1:{
			return true;
		}
		case 0:{
			a2 = a-1;
			b2 = b;
			break;
		}
		case 1:{
			a2 = a+1;
			b2 = b;
			break;
		}
		case 2:{
			a2 = a;
			b2 = b+1;
			break;
		}
		case 3:{
			a2 =a;
			b2 = b-1;
			break;
		}
		default : {
			throw new Error("fiste");
		}
		}


		removePercept(Literal.parseLiteral("case("+
				a2+","+(b2+TAILLE_DE_CUISINE_Y)+",vide)"));
		addPercept(Literal.parseLiteral("case("+
				a2+","+(b2+TAILLE_DE_CUISINE_Y)+","+agName+")"));

		if(map[a2][b2]==1 || map[a][b]==0){
			logger.info("ERREUR, DEADLOCK");
		}
		map[a2][b2] = 1;

		try {
			Thread.sleep(DUREE_DEPLACEMENT);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		map[a][b] = 0;

		fenetre.add_case_vide(a, b+TAILLE_DE_CUISINE_Y);
		fenetre.add_serveur(a2, b2+TAILLE_DE_CUISINE_Y, listeServeurs.indexOf(agName)%MAX_SERVEURS);
		removePercept(Literal.parseLiteral("case("+
				a+","+(b+TAILLE_DE_CUISINE_Y)+","+agName+")"));
		addPercept(Literal.parseLiteral("case("+
				a+","+(b+TAILLE_DE_CUISINE_Y)+",vide)"));
		return true;


	}








	private void confirmeEnregistreServeur(String agName, Term term, Term term2) {
		removePercept(agName, Literal.parseLiteral("serveurLocation("+term.toString()+","
				+term2.toString()+")"));
	}



	private void demandeAttributionCommande(String agName, Term term, Term Term2) {
		synchronized(verrou){
			Integer i = Integer.parseInt(term.toString());
			if(! commandesEnregistrees.contains(i)){
				addPercept(Literal.parseLiteral("commandeAttribuee(" +i+","+agName+","
						+Term2.toString()+")"));
				commandesEnregistrees.add(i);
			}
		}
	}


	private void enregistreCommande(String agName, Term term) {

		//		removePercept(Literal.parseLiteral("commandeAttribuee("+
		//				term.toString()+","+agName+")"));
		Integer idCommande = Integer.parseInt(term.toString());
		LinkedList<Integer>[] commande = nouvellesCommandes.get(idCommande);
		if(commande[0] != null){
			for(int i=0; i< commande[1].size(); i++){
				addPercept(agName,Literal.parseLiteral("nouvelleEntree("+idCommande+", "+
						commande[1].get(i)+","+i+",enregistre, "+agName+")"));
			}
		}
		if(commande[1] != null){
			for(int i=0; i< commande[1].size(); i++){
				addPercept(agName,Literal.parseLiteral("nouveauPlat("+idCommande+","+
						commande[1].get(i)+","+i+",enregistre, "+agName+")"));
			}
		}
		if(commande[2] != null){
			for(int i=0; i< commande[1].size(); i++){
				addPercept(agName,Literal.parseLiteral("nouveauDessert("+idCommande+", "+
						commande[1].get(i)+","+i+",enregistre, "+agName+")"));
			}
		}
		addPercept(agName,Literal.parseLiteral("commande("+idCommande+",enAttente,"+agName+")"));
	}

	private synchronized boolean enregistreServeur(String agName){
		if(! listeServeurs.contains(agName)){
			addPercept(agName, Literal.parseLiteral("selfServeur("+agName+")"));
			addPercept(Literal.parseLiteral("serveur("+agName+")"));
			listeServeurs.addLast(agName);
			//			spawn aléatoire
			Random r = new Random();
			int x = r.nextInt(TAILLE_DE_RESTAURANT_X);
			int y = r.nextInt(TAILLE_DE_RESTAURANT_Y);

			while(map[x][y] == 1){
				x = r.nextInt(TAILLE_DE_RESTAURANT_X);
				y = r.nextInt(TAILLE_DE_RESTAURANT_Y);	
			}
			logger.info("position du serveur "+agName+" : "+x+", "+y);
			map[x][y]=1;
			addPercept(agName, Literal.parseLiteral("serveurLocation("+x+","+
					(y+TAILLE_DE_CUISINE_Y)+")"));
			addPercept(Literal.parseLiteral("case("+x+","+
					(y+TAILLE_DE_CUISINE_Y)+","+agName+")"));
			removePercept(Literal.parseLiteral("case("+x+","+
					(y+TAILLE_DE_CUISINE_Y)+",vide)"));
			fenetre.add_serveur(x, y+TAILLE_DE_CUISINE_Y, (listeServeurs.indexOf(agName))%MAX_SERVEURS);
			logger.info("serveur dessiné");
			return true;
		}
		logger.info("Le serveur "+agName+" a demande a s'enregistrer mais ce nom est deja pris");
		return false;
	}

	private synchronized boolean enregistreCuisinier(String agName, Term term){
		Integer a = Integer.parseInt(term.toString());

		if(! listeCuisiniers.contains(agName)){
			addPercept(agName, Literal.parseLiteral("selfCuisinier("+agName+")"));
			addPercept(Literal.parseLiteral("cuisinier("+agName+")"));
			int i = listeCuisiniers.size();
			//Attribution d'une fonction au cuisinier
			if(a==0){
				//				Dans ce cas la c'est un chef
				if(listeChefs.size() ==0){
					fenetre.add_cuisinier(0, TAILLE_DE_CUISINE_Y-1, 0, agName);
					removePercept(Literal.parseLiteral("case("+0+
							","+(TAILLE_DE_CUISINE_Y-1)+",cuisine)"));
					addPercept(Literal.parseLiteral("case("+0+
							","+(TAILLE_DE_CUISINE_Y-1)+","+agName+")"));	
				}
				else{
					fenetre.add_cuisinier(TAILLE_DE_CUISINE_X-1, TAILLE_DE_CUISINE_Y-1, 0,agName);
					removePercept(Literal.parseLiteral("case("+(TAILLE_DE_CUISINE_X-1)+
							","+(TAILLE_DE_CUISINE_Y-1)+",cuisine)"));
					addPercept(Literal.parseLiteral("case("+(TAILLE_DE_CUISINE_X-1)+
							","+(TAILLE_DE_CUISINE_Y-1)+","+agName+")"));
				}
				addPercept(Literal.parseLiteral("fonction("+agName+",chef)"));
				listeChefs.addLast(agName);
			}
			else if(a==1){
				//met le cuisiniers au HashMap des plats finis.
				listeDePlatsPretsdeChaqueCuisinier.put(agName, 0);
				//				dans ce cas c'est un cuisinier simple
				if(listeCuisiniers.size()==0){
					fenetre.add_cuisinier(1, 1, 1,agName);
					removePercept(Literal.parseLiteral("case(1,2,vide)"));
					addPercept(Literal.parseLiteral("case(1,2,"+agName+")"));
					addPercept(Literal.parseLiteral("specialite("+agName+",entree)"));
				}
				else if(listeCuisiniers.size()==1){
					fenetre.add_cuisinier(4, 1, 2,agName);
					removePercept(Literal.parseLiteral("case(4,2,vide)"));
					addPercept(Literal.parseLiteral("case(4,2,"+agName+")"));
					addPercept(Literal.parseLiteral("specialite("+agName+",plat)"));
				}	
				else if(listeCuisiniers.size()==2){
					fenetre.add_cuisinier(7, 1, 3,agName);
					removePercept(Literal.parseLiteral("case(7,2,vide)"));
					addPercept(Literal.parseLiteral("case(7,2,"+agName+")"));
					addPercept(Literal.parseLiteral("specialite("+agName+",dessert)"));
				}	
				else if(listeCuisiniers.size()==3){
					fenetre.add_cuisinier(2, 1, 1,agName);
					removePercept(Literal.parseLiteral("case(2,2,vide)"));
					addPercept(Literal.parseLiteral("case(2,2,"+agName+")"));
					addPercept(Literal.parseLiteral("specialite("+agName+",entree)"));
				}	
				else if(listeCuisiniers.size()==4){
					fenetre.add_cuisinier(5, 1, 2,agName);
					removePercept(Literal.parseLiteral("case(5,2,vide)"));
					addPercept(Literal.parseLiteral("case(5,2,"+agName+")"));
					addPercept(Literal.parseLiteral("specialite("+agName+",plat)"));
				}	
				else if(listeCuisiniers.size()==5){
					fenetre.add_cuisinier(8, 1, 3,agName);
					removePercept(Literal.parseLiteral("case(8,2,vide)"));
					addPercept(Literal.parseLiteral("case(8,2,"+agName+")"));
					addPercept(Literal.parseLiteral("specialite("+agName+",dessert)"));
				}
				else {
					throw new Error("raté");
				}
				listeCuisiniers.addLast(agName);
			}

			//			A la fin de l'enregistrement des cuisiniers, on crée le réseau social
			if(listeCuisiniers.size()==6 && listeChefs.size()==2){
				for(int j=0; j<3; j++){
					for(int k=0; k<j; k++){
						addPercept(listeCuisiniers.get(j), Literal.parseLiteral("copain("+
								listeCuisiniers.get(j)+","+listeCuisiniers.get(k)+")"));
						addPercept(listeCuisiniers.get(k), Literal.parseLiteral("copain("+
								listeCuisiniers.get(k)+","+listeCuisiniers.get(j)+")"));
						addPercept(listeCuisiniers.get(j+3), Literal.parseLiteral("copain("+
								listeCuisiniers.get(j+3)+","+listeCuisiniers.get(k+3)+")"));
						addPercept(listeCuisiniers.get(k+3), Literal.parseLiteral("copain("+
								listeCuisiniers.get(k+3)+","+listeCuisiniers.get(j+3)+")"));
					}

					addPercept(listeCuisiniers.get(j), Literal.parseLiteral("copain("+
							listeCuisiniers.get(j)+","+listeCuisiniers.get(j+3)+")"));
					addPercept(listeCuisiniers.get(j+3), Literal.parseLiteral("copain("+
							listeCuisiniers.get(j+3)+","+listeCuisiniers.get(j)+")"));
					addPercept(listeCuisiniers.get(j), Literal.parseLiteral("copain("+
							listeCuisiniers.get(j)+","+listeChefs.get(0)+")"));
					addPercept(listeCuisiniers.get(j+3), Literal.parseLiteral("copain("+
							listeCuisiniers.get(j+3)+","+listeChefs.get(1)+")"));
					addPercept(listeChefs.get(0), Literal.parseLiteral("copain("+
							listeChefs.get(0)+","+listeCuisiniers.get(j)+")"));
					addPercept(listeChefs.get(1), Literal.parseLiteral("copain("+
							listeChefs.get(1)+","+listeCuisiniers.get(j+3)+")"));
				}
			}

			return true;
		}
		logger.info("Le cuisinier "+agName+" a demande a s'enregistrer mais ce nom est deja pris");
		return false;
	}

	/** Called before the end of MAS execution */
	@SuppressWarnings("deprecation")
	@Override
	public void stop() {
		runner.stop();
		super.stop();

	}

	private void addTempPercept() {
		addPercept(Literal.parseLiteral("case(0,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(1,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(2,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(3,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(4,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(5,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(6,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(7,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(8,0,cuisine)"));
		addPercept(Literal.parseLiteral("case(9,0,cuisine)"));

		addPercept(Literal.parseLiteral("case(0,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(1,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(2,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(3,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(4,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(5,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(6,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(7,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(8,1,cuisine)"));
		addPercept(Literal.parseLiteral("case(9,1,cuisine)"));

		//addPercept(Literal.parseLiteral("case(0,2,guichet)"));
		addPercept(Literal.parseLiteral("case(1,2,vide)"));
		addPercept(Literal.parseLiteral("case(2,2,vide)"));
		//		addPercept(Literal.parseLiteral("case(3,2,vide)"));
		addPercept(Literal.parseLiteral("case(4,2,vide)"));
		addPercept(Literal.parseLiteral("case(5,2,vide)"));
		//		addPercept(Literal.parseLiteral("case(6,2,vide)"));
		addPercept(Literal.parseLiteral("case(7,2,vide)"));
		addPercept(Literal.parseLiteral("case(8,2,vide)"));
		//	addPercept(Literal.parseLiteral("case(9,2,guichet)"));

		addPercept(Literal.parseLiteral("case(0,3,vide)"));
		addPercept(Literal.parseLiteral("case(1,3,vide)"));
		addPercept(Literal.parseLiteral("case(2,3,vide)"));
		addPercept(Literal.parseLiteral("case(3,3,vide)"));
		addPercept(Literal.parseLiteral("case(4,3,vide)"));
		addPercept(Literal.parseLiteral("case(5,3,vide)"));
		addPercept(Literal.parseLiteral("case(6,3,vide)"));
		addPercept(Literal.parseLiteral("case(7,3,vide)"));
		addPercept(Literal.parseLiteral("case(8,3,vide)"));
		addPercept(Literal.parseLiteral("case(9,3,vide)"));

		addPercept(Literal.parseLiteral("case(0,4,vide)"));
		addPercept(Literal.parseLiteral("case(1,4,vide)"));
		addPercept(Literal.parseLiteral("case(2,4,vide)"));
		addPercept(Literal.parseLiteral("case(3,4,vide)"));
		addPercept(Literal.parseLiteral("case(4,4,vide)"));
		addPercept(Literal.parseLiteral("case(5,4,vide)"));
		addPercept(Literal.parseLiteral("case(6,4,vide)"));
		addPercept(Literal.parseLiteral("case(7,4,vide)"));
		addPercept(Literal.parseLiteral("case(8,4,vide)"));
		addPercept(Literal.parseLiteral("case(9,4,vide)"));

		addPercept(Literal.parseLiteral("case(0,5,vide)"));
		addPercept(Literal.parseLiteral("case(1,5,table1)"));
		addPercept(Literal.parseLiteral("case(2,5,table1)"));
		addPercept(Literal.parseLiteral("case(3,5,vide)"));
		addPercept(Literal.parseLiteral("case(4,5,table2)"));
		addPercept(Literal.parseLiteral("case(5,5,table2)"));
		addPercept(Literal.parseLiteral("case(6,5,vide)"));
		addPercept(Literal.parseLiteral("case(7,5,table3)"));
		addPercept(Literal.parseLiteral("case(8,5,table3)"));
		addPercept(Literal.parseLiteral("case(9,5,vide)"));

		addPercept(Literal.parseLiteral("case(0,6,vide)"));
		addPercept(Literal.parseLiteral("case(1,6,table1)"));
		addPercept(Literal.parseLiteral("case(2,6,table1)"));
		addPercept(Literal.parseLiteral("case(3,6,vide)"));
		addPercept(Literal.parseLiteral("case(4,6,table2)"));
		addPercept(Literal.parseLiteral("case(5,6,table2)"));
		addPercept(Literal.parseLiteral("case(6,6,vide)"));
		addPercept(Literal.parseLiteral("case(7,6,table3)"));
		addPercept(Literal.parseLiteral("case(8,6,table3)"));
		addPercept(Literal.parseLiteral("case(9,6,vide)"));

		addPercept(Literal.parseLiteral("case(0,7,vide)"));
		addPercept(Literal.parseLiteral("case(1,7,table4)"));
		addPercept(Literal.parseLiteral("case(2,7,table4)"));
		addPercept(Literal.parseLiteral("case(3,7,vide)"));
		addPercept(Literal.parseLiteral("case(4,7,table5)"));
		addPercept(Literal.parseLiteral("case(5,7,table5)"));
		addPercept(Literal.parseLiteral("case(6,7,vide)"));
		addPercept(Literal.parseLiteral("case(7,7,table6)"));
		addPercept(Literal.parseLiteral("case(8,7,table6)"));
		addPercept(Literal.parseLiteral("case(9,7,vide)"));

		addPercept(Literal.parseLiteral("case(0,8,vide)"));
		addPercept(Literal.parseLiteral("case(1,8,table4)"));
		addPercept(Literal.parseLiteral("case(2,8,table4)"));
		addPercept(Literal.parseLiteral("case(3,8,vide)"));
		addPercept(Literal.parseLiteral("case(4,8,table5)"));
		addPercept(Literal.parseLiteral("case(5,8,table5)"));
		addPercept(Literal.parseLiteral("case(6,8,vide)"));
		addPercept(Literal.parseLiteral("case(7,8,table6)"));
		addPercept(Literal.parseLiteral("case(8,8,table6)"));
		addPercept(Literal.parseLiteral("case(9,8,vide)"));

		addPercept(Literal.parseLiteral("case(0,9,vide)"));
		addPercept(Literal.parseLiteral("case(1,9,table7)"));
		addPercept(Literal.parseLiteral("case(2,9,table7)"));
		addPercept(Literal.parseLiteral("case(3,9,vide)"));
		addPercept(Literal.parseLiteral("case(4,9,table8)"));
		addPercept(Literal.parseLiteral("case(5,9,table8)"));
		addPercept(Literal.parseLiteral("case(6,9,vide)"));
		addPercept(Literal.parseLiteral("case(7,9,table9)"));
		addPercept(Literal.parseLiteral("case(8,9,table9)"));
		addPercept(Literal.parseLiteral("case(9,9,vide)"));

		addPercept(Literal.parseLiteral("case(0,10,vide)"));
		addPercept(Literal.parseLiteral("case(0,11,guichet)"));
		addPercept(Literal.parseLiteral("case(1,10,table7)"));
		addPercept(Literal.parseLiteral("case(2,10,table7)"));
		addPercept(Literal.parseLiteral("case(3,10,vide)"));
		addPercept(Literal.parseLiteral("case(3,11,guichet)"));
		addPercept(Literal.parseLiteral("case(4,10,table8)"));
		addPercept(Literal.parseLiteral("case(5,10,table8)"));
		addPercept(Literal.parseLiteral("case(6,10,vide)"));
		addPercept(Literal.parseLiteral("case(6,11,guichet)"));
		addPercept(Literal.parseLiteral("case(7,10,table9)"));
		addPercept(Literal.parseLiteral("case(8,10,table9)"));
		addPercept(Literal.parseLiteral("case(9,10,vide)"));
		addPercept(Literal.parseLiteral("case(9,11,guichet)"));

	}

	private void createLocalMap() {
		for(int i=0; i<TAILLE_DE_RESTAURANT_X; i++){
			for(int j=0; j< TAILLE_DE_RESTAURANT_Y; j++){
				map[i][j] = 1;
			}
		}
		for(int i=0; i< TAILLE_DE_RESTAURANT_X; i++){
			map[i][0] = 0;
			map[i][1] = 0;
		}
		for(int i=2; i<TAILLE_DE_RESTAURANT_Y; i++){
			map[0][i] = 0;
			map[3][i] = 0;
			map[6][i] = 0;
			map[9][i] = 0;
		}


	}

	synchronized private int cherchePlusCourtChemin(String agName, Term term, Term term2, Term term3, Term term4) {

		removePercept(agName, Literal.parseLiteral("cheminBloque(_,_)"));
		//		Bidouille mais je ne vois pas comment faire autrement...
		removePercept(agName, Literal.parseLiteral("plusCourtChemin(sud)"));
		removePercept(agName, Literal.parseLiteral("plusCourtChemin(nord)"));
		removePercept(agName, Literal.parseLiteral("plusCourtChemin(est)"));
		removePercept(agName, Literal.parseLiteral("plusCourtChemin(ouest)"));

		Integer x = Integer.parseInt(term.toString());
		Integer y = Integer.parseInt(term2.toString()) - TAILLE_DE_CUISINE_Y;
		Integer a = Integer.parseInt(term3.toString());
		Integer b = Integer.parseInt(term4.toString()) - TAILLE_DE_CUISINE_Y;

		//		Liste des points atteignables depuis (x,y)
		int[][] atteignable = new int[TAILLE_DE_RESTAURANT_X][TAILLE_DE_RESTAURANT_Y];
		for(int i=0; i< TAILLE_DE_RESTAURANT_X; i++){
			for(int j=0; j< TAILLE_DE_RESTAURANT_Y; j++){
				atteignable[i][j]=-1;
			}
		}
		int[][] map2 = new int[TAILLE_DE_RESTAURANT_X][TAILLE_DE_RESTAURANT_Y]; 
		for(int i=0; i< TAILLE_DE_RESTAURANT_X; i++){
			for(int j=0; j< TAILLE_DE_RESTAURANT_Y; j++){
				map2[i][j] = map[i][j];
			}
		}

		if(map[x][y] == 1){
			addPercept(agName, Literal.parseLiteral("cheminBloque("+x+","+y+")"));
			return -1;
		}

		atteignable[x][y] = 0;
		//		Grosse bidouille pour permettre de faire marcher la recherche de plus court chemin : 
		map2[a][b] = 0;

		String s;

		//				logger.info("carte");
		//				for(int i=0; i< TAILLE_DE_RESTAURANT_Y; i++){
		//					s="";
		//					for(int j=0; j< TAILLE_DE_RESTAURANT_X; j++){
		//						s = s+" "+map[j][i];
		//					}
		//					logger.info(s);
		//				}


		parcoursDFS(map2,atteignable, x,y);
		//		s'il n'y a pas de chemin disponible


		//		logger.info("Table de routage");
		//		for(int i=0; i< TAILLE_DE_RESTAURANT_Y; i++){
		//			s="";
		//			for(int j=0; j< TAILLE_DE_RESTAURANT_X; j++){
		//				s = s+" "+atteignable[j][i];
		//			}
		//			logger.info(s);
		//		}

		//		logger.info("atteignable["+a+"]["+b+"] : "+atteignable[a][b]);


		if(atteignable[a][b] == -1){
			addPercept(agName, Literal.parseLiteral("cheminBloque("+x+","+y+")"));
			return -1;
		}



		if( a > 0 && atteignable[a-1][b] == atteignable[a][b]-1){
			//			logger.info("Plus court chemin ouest, distance "+atteignable[a-1][b]);
			addPercept(agName, Literal.parseLiteral("plusCourtChemin(ouest)"));
			return 0;
		}
		if( a < TAILLE_DE_RESTAURANT_X -1 && atteignable[a+1][b] == atteignable[a][b]-1){
			//			logger.info("Plus court chemin est, distance "+atteignable[a+1][b]);
			addPercept(agName, Literal.parseLiteral("plusCourtChemin(est)"));
			return 1;
		}
		if( b < TAILLE_DE_RESTAURANT_Y -1 && atteignable[a][b+1] == atteignable[a][b]-1){
			//			logger.info("Plus court chemin sud, distance "+atteignable[a][b+1]);
			addPercept(agName, Literal.parseLiteral("plusCourtChemin(sud)"));
			return 2;
		}
		if( b > 0 && atteignable[a][b-1] == atteignable[a][b]-1){
			//			logger.info("Plus court chemin nord, distance "+atteignable[a][b-1]);
			addPercept(agName, Literal.parseLiteral("plusCourtChemin(nord)"));
			return 3;
		}
		return -1;
	}

	private void parcoursDFS( int[][] map2, int[][] atteignable, Integer x, Integer y) {
		if(x > 0 && map2[x-1][y] ==0){
			if(atteignable[x-1][y] == -1 || atteignable[x-1][y] > atteignable[x][y]+1){
				atteignable[x-1][y] = atteignable[x][y]+1;
				parcoursDFS(map2,atteignable, x-1,y);
			}
		}
		if(x < TAILLE_DE_RESTAURANT_X -1 && map2[x+1][y] ==0){
			if(atteignable[x+1][y] == -1 || atteignable[x+1][y] > atteignable[x][y]+1){
				atteignable[x+1][y] = atteignable[x][y]+1;
				parcoursDFS(map2,atteignable, x+1,y);
			}
		}
		if(y > 0 && map2[x][y-1] ==0){
			if(atteignable[x][y-1] == -1 || atteignable[x][y-1] > atteignable[x][y]+1){
				atteignable[x][y-1] = atteignable[x][y]+1;
				parcoursDFS(map2,atteignable, x,y-1);
			}
		}
		if(y < TAILLE_DE_RESTAURANT_Y -1&& map2[x][y+1] ==0){
			if(atteignable[x][y+1] == -1 || atteignable[x][y+1] > atteignable[x][y]+1){
				atteignable[x][y+1] = atteignable[x][y]+1;
				parcoursDFS(map2,atteignable, x,y+1);
			}
		}
	}


	//TODO: fonctions:
	synchronized private boolean  platAttribue(String agName, Term plat, Term cuisinier,Term commande){

		//int commande2 = Integer.parseInt(commande.toString());
		logger.info("plat "+plat.toString()+" attribué au cuisinier "+agName);
		String log = "Le Cuisinier "+cuisinier.toString()+" a recu le plat "+plat.toString()+" de la commande "+commande.toString();
		logDeCuisiniersEtCommandes.add(log);
		fenetre.add_plat_au_four(agName);
		return true;	
	}

	private boolean  preparePlat(String agName, Term cuisinier, Term plat, Term chef,Term commande, Term positionTable){
		logger.info("plat "+plat.toString()+" en cours de préparation par le cuisinier "+agName);
		return true;	
	}

	private boolean  defineQualite(String agName, Term plat, Term qualite){


		if (qualite.toString()=="bonne"){
			nbDePlatAvecQualiteSuper++;
		}
		return true;
	}


	private boolean  platTermine(String agName, Term cuisinier, Term plat,Term commande){

		fenetre.remove_plat_au_four(agName);



		String log = "Le Cuisinier "+cuisinier.toString()+" a finit le plat "+plat.toString()+" de la commande "+commande.toString();
		logDeCuisiniersEtCommandes.add(log);
		fenetre.add_plat_a_table_cuisine(agName);

		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return true;
	}

}

